/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

#include "APP.h"
#include "STC8G_H_GPIO.h"
#include "STC8G_H_I2C.h"
#include "STC8G_H_NVIC.h"
#include "STC8G_H_Switch.h"

/*************	功能说明	**************

本例程基于STC8H8K64U为主控芯片的实验箱8进行编写测试，STC8G、STC8H系列芯片可通用参考.

读写RTC, IC为PCF8563.

用STC的MCU的IO方式驱动8位数码管。

使用Timer0的16位自动重装来产生1ms节拍,程序运行于这个节拍下, 用户修改MCU主时钟频率时,自动定时于1ms.

8位数码管显示时间(小时-分钟-秒).

行列扫描按键键码为17~32.

按键只支持单键按下, 不支持多键同时按下, 那样将会有不可预知的结果.

键按下超过1秒后,将以10键/秒的速度提供重键输出. 用户只需要检测KeyCode是否非0来判断键是否按下.

调整时间键:
键码17: 小时+.
键码18: 小时-.
键码19: 分钟+.
键码20: 分钟-.

下载时, 选择时钟 24MHz (可以在配置文件"config.h"中修改).

******************************************/

//========================================================================
//                               本地常量声明
//========================================================================

//========================================================================
//                               本地变量声明
//========================================================================

//========================================================================
//                               本地函数声明
//========================================================================

void IO_KeyScan(void);  // 50ms call
void DisplayRTC(void);
void ReadRTC(void);
void WriteRTC(void);

//========================================================================
//                            外部函数和变量声明
//========================================================================

//========================================================================
// 函数: RTC_init
// 描述: 用户初始化程序.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void RTC_init(void)
{
    u8 i;

    I2C_InitTypeDef I2C_InitStructure;
    I2C_InitStructure.I2C_Mode    = I2C_Mode_Master;  //主从选择   I2C_Mode_Master, I2C_Mode_Slave
    I2C_InitStructure.I2C_Enable  = ENABLE;           // I2C功能使能,   ENABLE, DISABLE
    I2C_InitStructure.I2C_MS_WDTA = DISABLE;          //主机使能自动发送,  ENABLE, DISABLE
    I2C_InitStructure.I2C_Speed   = 16;               //总线速度=Fosc/2/(Speed*2+4),      0~63
    I2C_Init(&I2C_InitStructure);
    NVIC_I2C_Init(I2C_Mode_Master, DISABLE, Priority_0);  //主从模式, I2C_Mode_Master, I2C_Mode_Slave; 中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

    P0_MODE_IO_PU(GPIO_Pin_All);             // P0 设置为准双向口
    P1_MODE_IO_PU(GPIO_Pin_4 | GPIO_Pin_5);  // P1.4,P1.5 设置为准双向口
    P6_MODE_IO_PU(GPIO_Pin_All);             // P6 设置为准双向口
    P7_MODE_IO_PU(GPIO_Pin_All);             // P7 设置为准双向口
    I2C_SW(I2C_P14_P15);                     // I2C_P14_P15,I2C_P24_P25,I2C_P33_P32
    display_index = 0;

    for (i = 0; i < 8; i++)
        LED8[i] = 0x10;  //上电消隐

    ReadRTC();
    F0 = 0;
    if (second >= 60)
        F0 = 1;  //错误
    if (minute >= 60)
        F0 = 1;  //错误
    if (hour >= 24)
        F0 = 1;  //错误
    if (F0)      //有错误, 默认12:00:00
    {
        second = 0;
        minute = 0;
        hour   = 12;
        WriteRTC();
    }

    DisplayRTC();
    LED8[2] = DIS_;
    LED8[5] = DIS_;

    KeyHoldCnt = 0;  //键按下计时
    KeyCode    = 0;  //给用户使用的键码

    IO_KeyState   = 0;
    IO_KeyState1  = 0;
    IO_KeyHoldCnt = 0;
    cnt50ms       = 0;
}

//========================================================================
// 函数: Sample_RTC
// 描述: 用户应用程序.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void Sample_RTC(void)
{
    DisplayScan();

    if (++msecond >= 1000)  // 1秒到
    {
        msecond = 0;
        ReadRTC();
        DisplayRTC();
    }

    if (++cnt50ms >= 50)  // 50ms扫描一次行列键盘
    {
        cnt50ms = 0;
        IO_KeyScan();
    }

    if (KeyCode != 0)  //有键按下
    {
        if (KeyCode == 17)  // hour +1
        {
            if (++hour >= 24)
                hour = 0;
            WriteRTC();
            DisplayRTC();
        }
        if (KeyCode == 18)  // hour -1
        {
            if (--hour >= 24)
                hour = 23;
            WriteRTC();
            DisplayRTC();
        }
        if (KeyCode == 19)  // minute +1
        {
            second = 0;
            if (++minute >= 60)
                minute = 0;
            WriteRTC();
            DisplayRTC();
        }
        if (KeyCode == 20)  // minute -1
        {
            second = 0;
            if (--minute >= 60)
                minute = 59;
            WriteRTC();
            DisplayRTC();
        }

        KeyCode = 0;
    }
}

//========================================================================
// 函数: DisplayRTC
// 描述: 显示时钟函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void DisplayRTC(void)
{
    if (hour >= 10)
        LED8[0] = hour / 10;
    else
        LED8[0] = DIS_BLACK;
    LED8[1] = hour % 10;
    LED8[2] = DIS_;
    LED8[3] = minute / 10;
    LED8[4] = minute % 10;
    LED8[6] = second / 10;
    LED8[7] = second % 10;
}

//========================================================================
// 函数: ReadRTC
// 描述: 读RTC函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void ReadRTC(void)
{
    u8 tmp[3];

    I2C_ReadNbyte(2, tmp, 3);
    second = ((tmp[0] >> 4) & 0x07) * 10 + (tmp[0] & 0x0f);
    minute = ((tmp[1] >> 4) & 0x07) * 10 + (tmp[1] & 0x0f);
    hour   = ((tmp[2] >> 4) & 0x03) * 10 + (tmp[2] & 0x0f);
}

//========================================================================
// 函数: WriteRTC
// 描述: 写RTC函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void WriteRTC(void)
{
    u8 tmp[3];

    tmp[0] = ((second / 10) << 4) + (second % 10);
    tmp[1] = ((minute / 10) << 4) + (minute % 10);
    tmp[2] = ((hour / 10) << 4) + (hour % 10);
    I2C_WriteNbyte(2, tmp, 3);
}

/*****************************************************
    行列键扫描程序
    使用XY查找4x4键的方法，只能单键，速度快

   Y     P04      P05      P06      P07
          |        |        |        |
X         |        |        |        |
P00 ---- K00 ---- K01 ---- K02 ---- K03 ----
          |        |        |        |
P01 ---- K04 ---- K05 ---- K06 ---- K07 ----
          |        |        |        |
P02 ---- K08 ---- K09 ---- K10 ---- K11 ----
          |        |        |        |
P03 ---- K12 ---- K13 ---- K14 ---- K15 ----
          |        |        |        |
******************************************************/

//========================================================================
// 函数: IO_KeyDelay
// 描述: 按键扫描延迟程序.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void IO_KeyDelay(void)
{
    u8 i;
    i = 60;
    while (--i)
        ;
}

//========================================================================
// 函数: IO_KeyScan
// 描述: 按键扫描程序.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2020-09-25
//========================================================================
void IO_KeyScan(void)  // 50ms call
{
    u8 j;

    j = IO_KeyState1;  //保存上一次状态

    P0 = 0xf0;  // X低，读Y
    IO_KeyDelay();
    IO_KeyState1 = P0 & 0xf0;

    P0 = 0x0f;  // Y低，读X
    IO_KeyDelay();
    IO_KeyState1 |= (P0 & 0x0f);
    IO_KeyState1 ^= 0xff;  //取反

    if (j == IO_KeyState1)  //连续两次读相等
    {
        j           = IO_KeyState;
        IO_KeyState = IO_KeyState1;
        if (IO_KeyState != 0)  //有键按下
        {
            F0 = 0;
            if (j == 0)
                F0 = 1;  //第一次按下
            else if (j == IO_KeyState) {
                if (++IO_KeyHoldCnt >= 20)  // 1秒后重键
                {
                    IO_KeyHoldCnt = 18;
                    F0            = 1;
                }
            }
            if (F0) {
                j = T_KeyTable[IO_KeyState >> 4];
                if ((j != 0) && (T_KeyTable[IO_KeyState & 0x0f] != 0))
                    KeyCode = (j - 1) * 4 + T_KeyTable[IO_KeyState & 0x0f] + 16;  //计算键码，17~32
            }
        } else
            IO_KeyHoldCnt = 0;
    }
    P0 = 0xff;
}
